//; ---------------------------------------------------------------------------
//; Object 1A - GHZ collapsing ledge
//; ---------------------------------------------------------------------------

#include "ledge.h"

#include "../../sprite.h"
#include "../../objectsystemNEWER.h"
#include "../../collision.h"

static object *obj;

#define player objects[0]
extern object *objects;

extern byte Ledge_SlopeData[];

//; ---------------------------------------------------------------------------
//; Sprite mappings - GHZ	collapsing ledge
//; ---------------------------------------------------------------------------
byte left[81] = { 0x10,
		 0xC8, 0xE, 0, 0x57, 0x10, //; ledge facing left
		 0xD0, 0xD, 0, 0x63, 0xF0,
		 0xE0, 0xD, 0, 0x6B, 0x10,
		 0xE0, 0xD, 0, 0x73, 0xF0,
		 0xD8,   6, 0, 0x7B, 0xE0,
		 0xD8,   6, 0, 0x81, 0xD0,
		 0xF0, 0xD, 0, 0x87, 0x10,
		 0xF0, 0xD, 0, 0x8F, 0xF0,
		 0xF0,   5, 0, 0x97, 0xE0,
		 0xF0,   5, 0, 0x9B, 0xD0,
		 0,    0xD, 0, 0x9F, 0x10,
		 0,	 5, 0, 0xA7, 0,
		 0,    0xD, 0, 0xAB, 0xE0,
		 0,	 5, 0, 0xB3, 0xD0,
		 0x10, 0xD, 0, 0xAB, 0x10,
		 0x10,   5, 0, 0xB7, 0
};
byte right[81] = { 0x10,
		 0xC8, 0xE, 0, 0x57, 0x10, // ; ledge facing right
		 0xD0, 0xD, 0, 0x63, 0xF0,
		 0xE0, 0xD, 0, 0x6B, 0x10,
		 0xE0, 0xD, 0, 0x73, 0xF0,
		 0xD8,   6, 0, 0x7B, 0xE0,
		 0xD8,   6, 0, 0xBB, 0xD0,
		 0xF0, 0xD, 0, 0x87, 0x10,
		 0xF0, 0xD, 0, 0x8F, 0xF0,
		 0xF0,   5, 0, 0x97, 0xE0,
		 0xF0,   5, 0, 0xC1, 0xD0,
		 0,    0xD, 0, 0x9F, 0x10,
		 0,	 5, 0, 0xA7,    0,
		 0,    0xD, 0, 0xAB, 0xE0,
		 0,	 5, 0, 0xB7, 0xD0,
		 0x10, 0xD, 0, 0xAB, 0x10,
		 0x10,   5, 0, 0xB7,    0
};
byte leftsmash[126] = { 0x19,
		 0xC8, 6, 0,	0x5D, 0x20,   //; ledge facing	left in	pieces
		 0xC8, 6, 0,	0x57, 0x10,
		 0xD0, 5, 0,	0x67,    0,
		 0xD0, 5, 0,	0x63, 0xF0,
		 0xE0, 5, 0,	0x6F, 0x20,
		 0xE0, 5, 0,	0x6B, 0x10,
		 0xE0, 5, 0,	0x77,    0,
		 0xE0, 5, 0,	0x73, 0xF0,
		 0xD8, 6, 0,	0x7B, 0xE0,
		 0xD8, 6, 0,	0x81, 0xD0,
		 0xF0, 5, 0,	0x8B, 0x20,
		 0xF0, 5, 0,	0x87, 0x10,
		 0xF0, 5, 0,	0x93,    0, 
		 0xF0, 5, 0,	0x8F, 0xF0,
		 0xF0, 5, 0,	0x97, 0xE0,
		 0xF0, 5, 0,	0x9B, 0xD0,
		 0,    5, 0,    0x8B, 0x20,
		 0,    5, 0,    0x8B, 0x10,
		 0,    5, 0,    0xA7,    0,
		 0,    5, 0,    0xAB, 0xF0,
		 0,    5, 0,    0xAB, 0xE0,
		 0,    5, 0,    0xB3, 0xD0,
		 0x10, 5, 0,	0xAB, 0x20,
		 0x10, 5, 0,	0xAB, 0x10,
		 0x10, 5, 0,	0xB7,    0
};
byte rightsmash[126] = { 0x19,
		 0xC8, 6, 0,	0x5D, 0x20,    //; ledge facing	right in pieces
		 0xC8, 6, 0,	0x57, 0x10,
		 0xD0, 5, 0,	0x67, 0,
		 0xD0, 5, 0,	0x63, 0xF0,
		 0xE0, 5, 0,	0x6F, 0x20,
		 0xE0, 5, 0,	0x6B, 0x10,
		 0xE0, 5, 0,	0x77, 0,
		 0xE0, 5, 0,	0x73, 0xF0,
		 0xD8, 6, 0,	0x7B, 0xE0,
		 0xD8, 6, 0,	0xBB, 0xD0,
		 0xF0, 5, 0,	0x8B, 0x20,
		 0xF0, 5, 0,	0x87, 0x10,
		 0xF0, 5, 0,	0x93, 0,
		 0xF0, 5, 0,	0x8F, 0xF0,
		 0xF0, 5, 0,	0x97, 0xE0,
		 0xF0, 5, 0,	0xC1, 0xD0,
		 0,    5, 0,    0x8B, 0x20,
		 0,    5, 0,    0x8B, 0x10,
		 0,    5, 0,    0xA7, 0,
		 0,    5, 0,    0xAB, 0xF0,
		 0,    5, 0,    0xAB, 0xE0,
		 0,    5, 0,    0xB7, 0xD0,
		 0x10, 5, 0,	0xAB, 0x20,
		 0x10, 5, 0,	0xAB, 0x10,
		 0x10, 5, 0,	0xB7, 0
};

byte *Map_Ledge[] = { left, right, leftsmash, rightsmash };

//==========

void (*Ledge_Index[6])() = { Ledge_Main, Ledge_Touch, Ledge_Collapse, Ledge_Display, Ledge_Delete, Ledge_WalkOff };

//OBJECT:					; XREF: Obj_Index
void CollapseLedge(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Ring_Index(pc,d0.w),d1
    //jmp	Ring_Index(pc,d1.w)
    (*Ledge_Index[routine])();
}

//; ===========================================================================

#define timedelay 0x38    //; time between touching the ledge and it collapsing
#define collapse  0x3A	  //; collapse flag

//Ledge_Main:	; Routine 0
void Ledge_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;
	
    //move.l	#Map_Ledge,obMap(a0)
    obj->Map = Map_Ledge;
	
    //move.w	#$4000,obGfx(a0)
    obj->Gfx = 0x4000;

    //ori.b	#4,obRender(a0)
    obj->Render = obj->Render | 4;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

    //move.b	#7,timedelay(a0) ; set time delay for collapse
    obj->Variables[timedelay-0x28] = 7;
	
    //move.b	#$64,obActWid(a0)
    obj->ActionWidth = 0x64;

    //move.b	obSubtype(a0),obFrame(a0)
    obj->Frame = obj->Subtype;

    //move.b	#$38,obHeight(a0)
    obj->Height = 0x38;

    //bset	#4,obRender(a0)
    //obj->Render = obj->Render | 16;
}

void Ledge_Touch()	//; Routine 2
{
    //tst.b	collapse(a0)	; is ledge collapsing?
    //beq.s	@slope		; if not, branch
    if (obj->Variables[collapse-0x28] != 0)
    {
        //tst.b	timedelay(a0)	; has time reached zero?
        //beq.w	Ledge_Fragment	; if yes, branch
        if (obj->Variables[timedelay-0x28] == 0) { Ledge_Fragment(obj); return;}
        else
        {
	    //subq.b	#1,timedelay(a0) ; subtract 1 from time
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;
        }
    }
           
    //@slope:
    //move.w	#$30,d1
    word slopeWidth = 48;  //some x-distance to slope object

    //lea	(Ledge_SlopeData).l,a2
    byte *slopeData = Ledge_SlopeData;

    //bsr.w	SlopeObject
    SlopeObject(obj, slopeWidth, slopeData);
 
    //bra.w	RememberState
    RememberState(obj);

    //; ===========================================================================
}

//; ===========================================================================
//; ===========================================================================



//Ledge_Collapse:	; Routine 4
void Ledge_Collapse()
{
    //tst.b	timedelay(a0)
    if (obj->Variables[timedelay-0x28] == 0)
    {
        //beq.w	loc_847A          //PART OF LEDGE_FRAGMENT IN COLLISION
        loc_847A(obj);
    }
    else
    {
        //move.b	#1,collapse(a0)	; set collapse flag
        obj->Variables[collapse-0x28] = 1;
	
	//subq.b	#1,timedelay(a0)
        obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;
        
        Ledge_WalkOff();
    }
}

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Ledge_WalkOff:	; Routine $A
void Ledge_WalkOff()
{
    //move.w	#$30,d1
    word ledgeWidth = 48;

    signed short distPlayerLedge;
    //bsr.w	ExitPlatform
    ExitPlatform(obj, ledgeWidth, distPlayerLedge);
		
    //move.w	#$30,d1
    word slopeWidth = 48;

    //lea	(Ledge_SlopeData).l,a2
    byte *slopeData = Ledge_SlopeData;

    //move.w	obX(a0),d2
    word slopeX = obj->X;

    //bsr.w	SlopeObject2
    SlopeObject2(obj, slopeWidth, slopeX, slopeData);

    //bra.w	RememberState
    RememberState(obj);

}   //; End of function Ledge_WalkOff

//; ===========================================================================

//Ledge_Display:	; Routine 6
void Ledge_Display()
{
    //tst.b	timedelay(a0)	; has time delay reached zero?
    //beq.s	Ledge_TimeZero	; if yes, branch
    if (obj->Variables[timedelay-0x28] == 0) { Ledge_TimeZero(); }
    else
    {
        //tst.b	collapse(a0)	; is ledge collapsing?
        //bne.w	loc_82D0	; if yes, branch
        if (obj->Variables[collapse-0x28] == 0)
        {
	    //subq.b	#1,timedelay(a0) ; subtract 1 from time
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;

	    //bra.w	DisplaySprite
            DisplaySprite(obj);
        }   //; ===========================================================================
        else
        {
            //loc_82D0:
	    //subq.b	#1,timedelay(a0)
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;

            //bsr.w	Ledge_WalkOff
            Ledge_WalkOff();

	    //lea	(v_player).w,a1
	    //btst	#3,obStatus(a1)
            //beq.s	loc_82FC
            if ((player.Status & 8) == 8)
            {
                //tst.b	timedelay(a0)
		//bne.s	locret_8308
		if (obj->Variables[timedelay-0x28] != 0) { return; }
                
                //bclr	#3,obStatus(a1)
                player.Status = player.Status - (player.Status & 8);

		//bclr	#5,obStatus(a1)
                player.Status = player.Status - (player.Status & 32);

		//move.b	#1,obNextAni(a1)
                player.NextAni = 1;
            }

            //loc_82FC:
	    //move.b	#0,collapse(a0)
            obj->Variables[collapse-0x28] = 0;

	    //move.b	#6,obRoutine(a0) ; run "Ledge_Display" routine
            obj->Routine = 6;

            //locret_8308:
	    //rts
        }
    }
}	

//; ===========================================================================

//Ledge_TimeZero:
void Ledge_TimeZero()
{
    //bsr.w	ObjectFall
    ObjectFall(obj);

    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //tst.b	obRender(a0)
    //bpl.s	Ledge_Delete
    if (obj->Render < 0x80) { Ledge_Delete(); }
		
}   //rts	

//; ===========================================================================

//Ledge_Delete:	; Routine 8
void Ledge_Delete()
{
    //bsr.w	DeleteObject
    DeleteObject(obj);

}   //rts	


//===============================
//#define timedelay 0x38
//#define collapse 0x3A

//; ===========================================================================
//; ---------------------------------------------------------------------------
//; Disintegration data for collapsing ledges (MZ, SLZ, SBZ)
//; ---------------------------------------------------------------------------
//CFlo_Data1:	
//		dc.b 
byte CFlo_Data1[26] = { 0x1C, 0x18, 0x14, 0x10, 0x1A, 0x16, 0x12,  0xE, 0xA, 6, 0x18, 0x14, 0x10, 0xC, 8, 4,
                        0x16, 0x12,  0xE,  0xA,    6,    2, 0x14, 0x10, 0xC, 0 };
byte CFlo_Data2[8] = {	0x1E, 0x16,  0xE,    6, 0x1A, 0x12,  0xA,    2 };
byte CFlo_Data3[8] = {	0x16, 0x1E, 0x1A, 0x12,    6,  0xE,  0xA,    2 };

//Ledge_Fragment:				; XREF: Obj1A_ChkTouch
void Ledge_Fragment(object *obj)
{
    //move.b	#0,collapse(a0)
    obj->Variables[collapse - 0x28] = 0;

    loc_847A(obj);
}

//loc_847A:				; XREF: Obj1A_Touch
void loc_847A(object *obj)
{
    //lea	(CFlo_Data1).l,a4
    byte *fragData = CFlo_Data1;

    //moveq	#$18,d1
    long numFragments = 24;

    //addq.b	#2,obFrame(a0)
    obj->Frame = obj->Frame + 2;

    //loc_8486:				; XREF: CFlo_Fragment
    //moveq	#0,d0
    //move.b	obFrame(a0),d0
    byte obFrame = obj->Frame;

    //add.w	d0,d0
    word mapOffset = obFrame;  //* 2 for size of a word pointer, no scaling in c

    
    //movea.l	obMap(a0),a3
    //adda.w	(a3,d0.w),a3
    byte *mapForFrame = obj->Map[mapOffset];

    //addq.w	#1,a3
    mapForFrame = mapForFrame + 1;     //skip mappings count

    #define currentBlock mapForFrame
    //from here on we change both the parent object and spawn additional objects to serve as children 
    //each child object/(fragment)'s mappings now points to a PORTION of the original object's mappings (a.k.a ONE block/five byte entry)
    
    //this means the RAW MAPPINGS flag has to be set, otherwise buildsprites will look for sub-mappings/multiple entrys when we only need a SINGLE entry
    //bset	#5,obRender(a0)
    obj->Render = obj->Render | 32;    

    //move.b	0(a0),d4
    byte parentID = obj->ID;

    //move.b	obRender(a0),d5
    byte parentRenderRaw = obj->Render;

    //movea.l	a0,a1
    object *childObj = obj;      //first child object will take place of the parent...

    //bra.s	loc_84B2
    //; ===========================================================================


    while (true)
    {
        //loc_84B2:
	//move.b	#6,obRoutine(a1)
        childObj->Routine = 6;

	//move.b	d4,0(a1)
        childObj->ID = parentID;

	//move.l	a3,obMap(a1)
        childObj->Map = (byte**)currentBlock;

	//move.b	d5,obRender(a1)
        childObj->Render = parentRenderRaw;

	//move.w	obX(a0),obX(a1)
        childObj->X = obj->X;

	//move.w	obY(a0),obY(a1)
        childObj->Y = obj->Y;

	//move.w	obGfx(a0),obGfx(a1)
        childObj->Gfx = obj->Gfx;
	
	//move.b	obPriority(a0),obPriority(a1)
        childObj->Priority = obj->Priority;
	
	//move.b	obActWid(a0),obActWid(a1)
        childObj->ActionWidth = obj->ActionWidth;
	
	//move.b	(a4)+,timedelay(a1)
        childObj->Variables[timedelay - 0x28] = *(fragData++);

	//cmpa.l	a0,a1
	//bhs.s	loc_84EE
        //bsr.w	DisplaySprite1
        if (childObj > obj) { DisplaySprite(childObj); }   //we don't need multiple displaysprite routines...
   
        //loc_84EE:
	//dbf	d1,loc_84AA
        if ((numFragments--) < 0) { break; }
         
        //loc_84AA:
	//bsr.w	FindFreeObj
        childObj = FindFreeObj();
 
	//bne.s	loc_84F2
        if (childObj->ID != 0) { break; }
 
	//addq.w	#5,a3
        currentBlock = currentBlock + 5;     //next mappings block
    }

    //loc_84F2:
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //sfx	sfx_Collapse,1	; play collapsing sound
}   


